# # -*- coding: utf-8 -*-
# # @FileName : model.py
# # @Author   : wangxinyao
# # @Time     : 2025/2/19 09:17
# 1.模型约束描述
# 1)数据集加载与预处理
from keras.src.datasets.mnist import load_data
import matplotlib.pyplot as plt
(x_train,y_train),(x_test,y_test)=load_data()
print(x_train.shape)
x_train=x_train.reshape(-1,28,28,1)/255
x_test=x_test.reshape(-1,28,28,1)/255
from keras.src.utils import to_categorical
y_test=to_categorical(y_test)
y_train=to_categorical(y_train)
# 代码从MNIST数据库中加载手写数字的训练和测试数据集。
# 加载的数据集必须包含图像数据和对应的标签。
# 图像数据被重新塑形为(-1, 28, 28, 1)的维度，并且被归一化到[0,1]区间，这是神经网络模型通常需要的预处理步骤。
# 图像数据增强技术的应用，实现随机翻转、旋转、裁剪等图像数据增强。
from keras import metrics,Model,losses,layers,Sequential,optimizers,activations
# 2)模型构建
# 代码定义了一个名为AlexNet的类，该类继承自Model类，用于构建神经网络模型。
# AlexNet模型必须包含一个卷积层序列（self.conv），一个展平层（self.flat），以及一个全连接层序列（self.fc）。
# 卷积层序列由五个卷积层和三个最大池化层组成，具体的层数和参数（如滤波器数量、卷积核大小等）在图中已固定。
#
# 全连接层序列由两个隐藏层（每层64个神经元，激活函数为ReLU）和一个输出层（10个神经元，激活函数为softmax）组成，用于分类0-9的手写数字。
# 3)模型编译
# 在模型编译时，必须使用Adam优化器、稀疏分类交叉熵损失函数，并且以准确率作为评估指标。
# 4)模型训练
# 模型使用训练集（x_train和y_train）进行训练，批次大小为100，训练轮次（epoch）为10。
# 训练过程中，模型会根据设定的损失函数和优化器来更新其权重。
# 分批次训练后，可视化展示loss、分类精度等指标的变化情况。
class AlexNet(Model):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.conv=Sequential([
            layers.Conv2D(filters=6,kernel_size=(3,3),activation=activations.relu,padding='same'),
            layers.MaxPool2D(),
            layers.Conv2D(filters=16, kernel_size=(3, 3), activation=activations.relu, padding='same'),
            layers.MaxPool2D(),
            layers.Conv2D(filters=24, kernel_size=(3, 3), activation=activations.relu, padding='same'),
            layers.Conv2D(filters=24, kernel_size=(3, 3), activation=activations.relu, padding='same'),
            layers.Conv2D(filters=24, kernel_size=(3, 3), activation=activations.relu, padding='same'),
            layers.MaxPool2D()
        ])
        self.flat=layers.Flatten()
        self.de=Sequential([
            layers.Dense(units=64,activation=activations.relu),
            layers.Dense(units=64, activation=activations.relu),
            layers.Dense(units=10, activation=activations.softmax)
        ])
    def call(self,inputs, *args, **kwargs):
        inputs=self.conv(inputs)
        inputs=self.flat(inputs)
        inputs=self.de(inputs)
        return inputs
if __name__ == '__main__':
    model=AlexNet()
    model.build((None,28,28,1))
    model.summary()
    model.compile(optimizer=optimizers.Adam(),loss=losses.categorical_crossentropy,metrics=['acc'])
    history=model.fit(x_train,y_train,epochs=10,batch_size=100,validation_data=(x_test,y_test))
    acc=history.history['acc']
    val_acc=history.history['val_acc']
    loss=history.history['loss']
    val_loss=history.history['val_loss']
    plt.plot(acc)
    plt.plot(val_acc)
    plt.plot(loss)
    plt.plot(val_loss)
    plt.show()
    import random
    import numpy as np

    index = random.randint(0, len(x_test) - 1)
    img = x_test[index]
    predict = model.predict(x_test)[index]
    predict = np.argmax(predict)
    plt.imshow(img)
    plt.title(predict)
    plt.show()
    model.save_weights('model.weights.h5')
    model.load_weights('model.weights.h5')
    model.evaluate(x_train, y_train)
'''
    model.compile(optimizer=optimizers.Adam(),loss=losses.categorical_crossentropy,metrics=['acc'])
    history=model.fit(x_train,y_train,epochs=10,batch_size=100,validation_data=(x_test,y_test))
    acc: 0.9926 - loss: 0.0221 - val_acc: 0.9898 - val_loss: 0.0333
    随着训练次数增加 准确率越来越高，损失率越来越低，但是损失函数还是有点大 需要调优

'''
'''
    model.compile(optimizer=optimizers.Adam(),loss=losses.categorical_crossentropy,metrics=['acc'])
    history=model.fit(x_train,y_train,epochs=10,batch_size=10,validation_data=(x_test,y_test))
    step - acc: 0.9914 - loss: 0.0299 - val_acc: 0.9853 - val_loss: 0.0484
    
    model.compile(optimizer=optimizers.Adam(),loss=losses.categorical_crossentropy,metrics=['acc'])
    history=model.fit(x_train,y_train,epochs=10,batch_size=100,validation_data=(x_test,y_test))
    acc: 0.9926 - loss: 0.0221 - val_acc: 0.9898 - val_loss: 0.0333
    
    model.compile(optimizer=optimizers.Adam(),loss=losses.categorical_crossentropy,metrics=['acc'])
    history=model.fit(x_train,y_train,epochs=10,batch_size=1000,validation_data=(x_test,y_test))
    step - acc: 0.9796 - loss: 0.0657 - val_acc: 0.9811 - val_loss: 0.0538
    
    batch_size=1000是最优的
'''
# 5)模型评估与保存
# 训练完成后，模型使用测试集（x_test和y_test）进行评估，以测试其性能。
# 模型的权重被保存到名为'model.h5'的文件中，以便后续使用或进一步分析。


